//! Konfiguracijska datoteka za 'arh' sloj

#ifndef _ARH_SPREMNIK_H_
#define _ARH_SPREMNIK_H_

#ifndef	_ARH_PREKIDI_S_

#include "tipovi.h"

void arh_inicijalizacija_segmenata ();
void arh_azuriraj_tss_esp0 (void *esp0);

static inline uint32 arh_pomak()
{
	extern char programi_pocetak, programi_pocetak_rel;
	return ((uint32) &programi_pocetak) - ((uint32) &programi_pocetak_rel);
}

//pretvara adresu jezgre u adresu za program
static inline void *arh_jup(void *adr_u_jezgri)
{
	return (void *) ( ((uint32) adr_u_jezgri) - arh_pomak());
}

//pretvara adresu programa u adresu koja je dohvatljiva iz jezgre
static inline void *arh_puj(void *adr_u_programu)
{
	return (void *) ( ((uint32) adr_u_programu) + arh_pomak());
}

//vraca velicinu programa
static inline uint arh_vel_prog(void *param)
{
	extern char programi_velicina;

	return (uint) &programi_velicina;
}

#endif

#define SEGJ_INSTR	1
#define SEGJ_PODACI	2
#define SEG_TSS		3
#define SEG_INSTR	4
#define SEG_PODACI	5
//aziriraj ako mjenjas GDT!

#define GDT	0
#define LDT	1

#define RAZINA_JEZGRE		0
#define RAZINA_KORISNIKA	3

#define GDT_OPISNIK(ID, TABLICA, PRIV_RAZINA)			\
	( (PRIV_RAZINA) | ((TABLICA) << 2) | ((ID) << 3) )

#ifdef _ARH_SPREMNIK_C_

static void arh_azuriraj_opisnik_segmenta (int id, void *poc_adr, uint32 vel,
					   int razina);
//static void arh_ispisi_gdt_zapis(int id);

//zapisi u GDT
typedef struct _gdt_t_ {
	uint16	segm_limit0;	//segment limit, bitovi: 15:00		(00-15)
	uint16	base_addr0;	//pocetna adresa, bitovi: 15:00		(16-31)
	uint8	base_addr1;	//pocetna adresa, bitovi: 23:16		(32-38)
	uint8	type	: 4;	//tip segmenta				(39-42)
	uint8	S	: 1;	//tip opisnika: 0-system, 1-kod ili pod.(43-43)
	uint8	DPL	: 2;	//razina prioriteta opisnika		(44-45)
	uint8	P	: 1;	//prisutan (u mem.)			(46-46)
	uint8	segm_limit1: 4;	//segment limit, bitovi: 19:16		(47-50)
	uint8	AVL	: 1;	//"Available for use by system software"(51-51)
	uint8	L	: 1;	//64-bitni segment koda? (inace nebitan)(52-52)
	uint8	DB	: 1;	//1 za 32 bitne sustave, 0 za 16 bitne	(53-53)
	uint8	G	: 1;	//granularnost 0-1B, 1-4kB (za rac.lim.)(54-54)
	uint8	base_addr2;	//pocetna adresa, bitovi: 31:24		(55-63)
	
} __attribute__((__packed__)) gdt_t;

//GDTR (registar)
typedef struct _gdtr_t_ {
	uint16 limit;
	gdt_t *gdt;
} __attribute__((__packed__)) gdtr_t;


//opisnik za zadatak - TSS
typedef struct _tss_t_ {
	uint32	op_preth;	//ne koristi se

	uint32	esp0;		//kazaljka stoga za obradu prekida (prsten 0)!
	uint16	ss0;		//segment za stog - prsten 0
	uint16	ss0popuna;

	uint32	esp1, ss1, esp2, ss2; //prsteni 1 i 2 se ne koriste

	uint32	cr3;		//kontrolni registar cr3 (stranicenje)

	//mjesto za "kontekst" - ne koristi se!
	uint32	eip, eflags, reg[8], seg[6];

	uint32	ldt;		//opisnik za LDT tablicu (ne koristi se)

	uint16	zamka;		//ne koristi se;

	uint16	ui_mapa;	//koji su UI dozvoljeni
} __attribute__((__packed__)) tss_t;


//prvi zapis u gdt-u je prazan (mora biti!)
#define GDT_0	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}

/* svih 4 GB za kod (r-x) */
#define GDT_INSTRUKCIJE_JEZGRE			\
	{	0xffff,	/* segm_limit0	*/	\
		0,	/* base_addr0	*/	\
		0,	/* base_addr1	*/	\
		0x0a,	/* type	r-x	*/	\
		1,	/* S		*/	\
		0,	/* DPL		*/	\
		1,	/* P		*/	\
		0x0f,	/* segm_limit1	*/	\
		0,	/* AVL		*/	\
		0,	/* L		*/	\
		1,	/* DB		*/	\
		1,	/* G		*/	\
		0	/* base_addr2	*/	\
	}

/* svih 4 GB za podatke (rw-)*/
#define GDT_PODACI_JEZGRE			\
	{	0xffff,	/* segm_limit0	*/	\
		0,	/* base_addr0	*/	\
		0,	/* base_addr1	*/	\
		0x02,	/* type	rw-	*/	\
		1,	/* S		*/	\
		0,	/* DPL		*/	\
		1,	/* P		*/	\
		0x0f,	/* segm_limit1	*/	\
		0,	/* AVL		*/	\
		0,	/* L		*/	\
		1,	/* DB		*/	\
		1,	/* G		*/	\
		0	/* base_addr2	*/	\
	}

/* svih 4 GB za kod (r-x) */
#define GDT_INSTRUKCIJE_PROGRAMA		\
	{	0xffff,	/* segm_limit0	*/	\
		0,	/* base_addr0	*/	\
		0,	/* base_addr1	*/	\
		0x0a,	/* type	r-x	*/	\
		1,	/* S		*/	\
		3,	/* DPL		*/	\
		1,	/* P		*/	\
		0x0f,	/* segm_limit1	*/	\
		0,	/* AVL		*/	\
		0,	/* L		*/	\
		1,	/* DB		*/	\
		1,	/* G		*/	\
		0	/* base_addr2	*/	\
	}

/* svih 4 GB za podatke (rw-)*/
#define GDT_PODACI_PROGRAMA			\
	{	0xffff,	/* segm_limit0	*/	\
		0,	/* base_addr0	*/	\
		0,	/* base_addr1	*/	\
		0x02,	/* type	rw-	*/	\
		1,	/* S		*/	\
		3,	/* DPL		*/	\
		1,	/* P		*/	\
		0x0f,	/* segm_limit1	*/	\
		0,	/* AVL		*/	\
		0,	/* L		*/	\
		1,	/* DB		*/	\
		1,	/* G		*/	\
		0	/* base_addr2	*/	\
	}


/* TSS - "opisnik zadataka" podrzan od strane procesora */
#define GDT_TSS					\
	{	sizeof(tss_t),	/* segm_limit0	*/	\
		0,	/* base_addr0	*/	\
		0,	/* base_addr1	*/	\
		0x09,	/* 10B1 = 1001	*/	\
		0,	/* -		*/	\
		0,	/* DPL		*/	\
		1,	/* P		*/	\
		0x00,	/* segm_limit1	*/	\
		0,	/* AVL		*/	\
		0,	/* L		*/	\
		0,	/* DB		*/	\
		0,	/* G		*/	\
		0	/* base_addr2	*/	\
	}


#endif	/* _ARH_SPREMNIK_C_ */
#endif	/* _ARH_SPREMNIK_H_ */
